package com.sdx.console.transaction.web;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.ibeetl.admin.core.annotation.Function;
import com.ibeetl.admin.core.entity.CoreUser;
import com.ibeetl.admin.core.file.FileItem;
import com.ibeetl.admin.core.file.FileService;
import com.ibeetl.admin.core.service.CorePlatformService;
import com.ibeetl.admin.core.util.DateUtil;
import com.ibeetl.admin.core.util.PlatformException;
import com.ibeetl.admin.core.util.UUIDUtil;
import com.ibeetl.admin.core.util.ValidateConfig;
import com.ibeetl.admin.core.web.AuthorizedBaesController;
import com.ibeetl.admin.core.web.JsonResult;
import com.ibeetl.admin.core.web.JsonReturnCode;
import com.sdx.common.entity.ResCloudFile;
import com.sdx.common.service.ResCloudFileService;
import com.sdx.common.utils.FileUtils;
import com.sdx.common.utils.JacksonUtils;
import com.sdx.console.common.ControllerUtils;
import com.sdx.console.common.service.BaseDataService;
import com.sdx.console.order.service.FinOrderService;
import com.sdx.console.system.entity.ChannelSet;
import com.sdx.console.system.service.ChannelSetService;
import com.sdx.console.transaction.entity.FinTransForRefund;
import com.sdx.console.transaction.entity.FinTransaction;
import com.sdx.console.transaction.entity.FinTransactionRefund;
import com.sdx.console.transaction.service.FinTransactionRefundService;
import com.sdx.console.transaction.service.FinTransactionService;
import com.sdx.console.transaction.web.query.FinTransactionQuery;
import com.sdx.payment.RefundResult;
import com.sdx.payment.service.IPaymentService;
import com.sdx.payment.wxpay.WxpayService;
import com.sdx.service.ConfigService;
import com.sdx.third.AliOSSApi;
import org.apache.commons.lang3.StringUtils;
import org.beetl.core.GroupTemplate;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.engine.PageQuery;
import org.jxls.common.Context;
import org.jxls.util.JxlsHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * FinTransaction 接口
 */
@RequestMapping("/trans/finTransaction")
@Controller
public class FinTransactionController extends AuthorizedBaesController {

	private static final Logger log = LoggerFactory.getLogger(FinTransactionController.class);
    private static final String MODEL = "/trans/finTransaction";

    private static final String SQL_PREFIX = "trans.finTransaction";

    @Autowired private FinTransactionService finTransactionService;

	@Autowired
	CorePlatformService platformService;

    @Autowired
    FileService fileService;

    @Autowired
    private FinTransactionRefundService refundService;

    @Autowired
    private WxpayService wxpayService;

	@Resource
	GroupTemplate groupTemplate;

    @Resource
    private FinOrderService finOrderService;

    @Resource
    private CorePlatformService corePlatformService;

    @Resource
    private ChannelSetService channelSetService;

    @Resource
    private BaseDataService baseDataService;

    @Resource
    private ResCloudFileService resCloudFileService;

    @Resource
    private SQLManager sqlManager;

	/**
	 * 返回退款页面，显示订单总金额，可退金额
	 * @param transactionId
	 * @return
	 */
	@RequestMapping("/refund.do")
	@Function("trans.finTransaction.refund")
	public ModelAndView refundPage(String transactionId) {
		ModelAndView view = new ModelAndView(MODEL + "/refund.html") ;
		FinTransForRefund refund = finTransactionService.selectTransForRefund(transactionId);

		if (refund==null){
			view.addObject(ControllerUtils.VIEW_ERROR_MSG,"交易单不存在。");
		} else if (refund.getPayFlag().intValue()!=2
				|| refund.getRefundMoney().longValue()>=refund.getTotalMoney().longValue()) {
			view.addObject(ControllerUtils.VIEW_ERROR_MSG,"交易单不是已付款状态，或已经全款退还。");
		}
		refund.setTransactionId(transactionId);
		view.addObject("refund",refund);
		return view;
	}

	@PostMapping("/refund.json")
	@Function("trans.finTransaction.refund")
	@ResponseBody
    public JsonResult refund(@RequestParam(required = true)String transactionId,
	                         @RequestParam(required = true)String reason,
	                         @RequestParam(required = true) int refundMoney) {
		JsonResult result;
		FinTransForRefund refund = finTransactionService.selectTransForRefund(transactionId);
		FinTransaction transaction = finTransactionService.queryById(transactionId);
		String errMsg = null;
		if (refund==null || transaction==null){
			errMsg = "交易单不存在。";
		} else if (refund.getPayFlag().intValue()!=2
				|| refund.getRefundMoney().longValue()>=refund.getTotalMoney().longValue()) {
			errMsg = "交易单不是已付款状态，或已经全款退还。";
		}
		if (errMsg!=null) {
			result = JsonResult.failMessage(errMsg);
			return result;
		}
		CoreUser user = platformService.getCurrentUser();
		FinTransactionRefund transactionRefund = new FinTransactionRefund();
		//1、生成退款记录
		transactionRefund.setOperatorId(user.getId().intValue());
		transactionRefund.setOperatorName(user.getName());
		transactionRefund.setRefundTime(new Date());
		transactionRefund.setRefundApply((long)refundMoney);
		transactionRefund.setRefundId(UUIDUtil.uuid());
		transactionRefund.setRefundReason(reason);
		transactionRefund.setRefundStatus(0);
		transactionRefund.setTransactionId(transactionId);
		refundService.save(transactionRefund);

		//2、调用退款接口
		IPaymentService paymentService = null;
		if (transaction.getPayMethod()>0 && transaction.getPayMethod()<10) {
			//微信支付
			paymentService = wxpayService;
		} else if (transaction.getPayMethod()>10 && transaction.getPayMethod()<20) {

		} else if (transaction.getPayMethod()>20 && transaction.getPayMethod()<30) {

		}
		if(paymentService!=null){
            RefundResult refundResult = paymentService.refund(transactionRefund.getRefundId(),refundMoney,transaction);
            //3、更新退款状态
            FinTransactionRefund updateRefund = new FinTransactionRefund();
            updateRefund.setRefundId(transactionRefund.getRefundId());
            if (refundResult.getResultCode()!=1) {
                updateRefund.setRefundStatus(-1);
                updateRefund.setErrorMsg(refundResult.getMessage());
                refundService.updateTemplate(updateRefund);
                return JsonResult.failMessage("退款失败，"+refundResult.getMessage());
            } else {
                updateRefund.setRefundStatus(1);
                updateRefund.setErrorMsg("接口调用成功。");
                updateRefund.setRefundMoney(refundResult.getRefundMoney());
                refundService.updateTemplate(updateRefund);
            }
		}
		return JsonResult.success();
    }
    /* 页面 */

    @GetMapping("/index.do")
    @Function("trans.finTransaction.query")
    @ResponseBody
    public ModelAndView index(HttpServletRequest request) {
        ModelAndView view = new ModelAndView(MODEL + "/index.html") ;
	    Map<String, Object> var = new HashMap<>(5);
	    var.put("jsVer", System.currentTimeMillis());
        view.addObject("orderTypes",finOrderService.selectOrderType(null));
	    groupTemplate.setSharedVars(var);
        CoreUser user = getLoginUser(request);
        Integer accessType = corePlatformService.getAccessType(request);
        List<ChannelSet> channelList = channelSetService.selectAuthChannels(accessType, user.getOrgId(),user.getTenantId());
        view.addObject("channelList",channelList);
        return view;
    }

    @GetMapping("/edit.do")
    @Function("trans.finTransaction.edit")
    @ResponseBody
    public ModelAndView edit(String transactionId) {
        ModelAndView view = new ModelAndView(MODEL + "/add.html");
        FinTransaction finTransaction = finTransactionService.queryById(transactionId);
        view.addObject("finTransaction", finTransaction);
		try {
			view.addObject("finTransactionJson", JacksonUtils.toJsonString(finTransaction,JacksonUtils.DF1));
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
        return view;
    }

    @GetMapping("/add.do")
    @Function("trans.finTransaction.add")
    @ResponseBody
    public ModelAndView add() {
        ModelAndView view = new ModelAndView(MODEL + "/add.html");
        return view;
    }

    /* ajax json */

    @PostMapping("/list.json")
    @Function("trans.finTransaction.query")
    @ResponseBody
    public JsonResult<PageQuery> list(FinTransaction condtion,HttpServletRequest request)
    {
        CoreUser user = getLoginUser(request);
        condtion.setTenantId(user.getTenantId());
        PageQuery page = condtion.getPageQuery();
        finTransactionService.queryByCondition(page);
        return JsonResult.success(page);
    }

    private JsonResult save(boolean isNew,FinTransaction finTransaction
	) {
    	JsonResult result = JsonResult.success();
		String dir = DateUtil.now("yyyyMMdd");
    	String subPath = "/images/cover/"+dir+"/";


    	if (isNew) {
			finTransactionService.save(finTransaction);
		} else {
			finTransactionService.updateTemplate(finTransaction);
		}
		return result;
	}
    @PostMapping("/add.json")
    @Function("trans.finTransaction.add")
    @ResponseBody
    public JsonResult add(@Validated(ValidateConfig.ADD.class)FinTransaction finTransaction
		)
    {

        return save(true,finTransaction
		);
    }

    @PostMapping("/update.json")
    @Function("trans.finTransaction.edit")
    @ResponseBody
    public JsonResult<String> update(@Validated(ValidateConfig.UPDATE.class)  FinTransaction finTransaction
		) {
		return save(false,finTransaction
		);
    }



    @GetMapping("/view.json")
    @Function("trans.finTransaction.query")
    @ResponseBody
    public JsonResult<FinTransaction>queryInfo(String transactionId) {
        FinTransaction finTransaction = finTransactionService.queryById( transactionId);
        return  JsonResult.success(finTransaction);
    }

    @PostMapping("/delete.json")
    @Function("trans.finTransaction..del")
    @ResponseBody
    public JsonResult delete(String ids) {
        if (ids.endsWith(",")) {
            ids = StringUtils.substringBeforeLast(ids, ",");
        }
        //List<Long> idList = ConvertUtil.str2longs(ids);
		List<String> idList = new ArrayList<String>();
		Collections.addAll(idList,ids.split(","));
        finTransactionService.batchDelFinTransaction(idList);
        return JsonResult.success();
    }


    @PostMapping("/excel/export.json")
    @Function("trans.finTransaction.export")
    @ResponseBody
    public JsonResult<String> export(HttpServletResponse response,FinTransactionQuery condtion,HttpServletRequest request) {
        /**
         * 1)需要用你自己编写一个的excel模板
         * 2)通常excel导出需要关联更多数据，因此finTransactionService.queryByCondition方法经常不符合需求，需要重写一个为模板导出的查询
         * 3)参考ConsoleDictController来实现模板导入导出
         */
        CoreUser user = getLoginUser(request);
        condtion.setTenantId(user.getTenantId());
        String excelTemplate ="excelTemplates/trans/finTransaction/你的excel模板文件名字.xls";
        PageQuery<FinTransaction> page = condtion.getPageQuery();
        //取出全部符合条件的
        page.setPageSize(Integer.MAX_VALUE);
        page.setPageNumber(1);
        page.setTotalRow(Integer.MAX_VALUE);
        //本次导出需要的数据
        List<FinTransaction> list =finTransactionService.queryByCondition(page).getList();
        try(InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(excelTemplate)) {
            if(is==null) {
                throw new PlatformException("模板资源不存在："+excelTemplate);
            }
            FileItem item = fileService.createFileTemp("FinTransaction_"+DateUtil.now("yyyyMMddHHmmss")+".xls");
            OutputStream os = item.openOutpuStream();
            Context context = new Context();
            context.putVar("list", list);
            JxlsHelper.getInstance().processTemplate(is, os, context);
            os.close();
            //下载参考FileSystemContorller
            return  JsonResult.success(item.getPath());
        } catch (IOException e) {
            throw new PlatformException(e.getMessage());
        }

    }

    @PostMapping("/excel/import.do")
    @Function("trans.finTransaction.import")
    @ResponseBody
    public JsonResult importExcel(@RequestParam("file") MultipartFile file) throws Exception {
        if (file.isEmpty()) {
           return JsonResult.fail();
        }
        InputStream ins = file.getInputStream();
        /*解析模板并导入到数据库里,参考DictConsoleContorller，使用jxls reader读取excel数据*/
        ins.close();
        return JsonResult.success();
    }
     //==================== 虚拟订单 =========================
    @GetMapping("/virtual.do")
    @Function("trans.finTransaction.virtual.query")
    @ResponseBody
    public ModelAndView orderIndex(HttpServletRequest request,String channelCode,String comefrom,String transactionId) {
        ModelAndView view = new ModelAndView(MODEL + "/virtual.html") ;
        Map<String, Object> var = new HashMap<>(5);
        var.put("jsVer", System.currentTimeMillis());
        view.addObject("orderTypes",finOrderService.selectOrderType(3));
        groupTemplate.setSharedVars(var);
        CoreUser user = getLoginUser(request);
        Integer accessType = corePlatformService.getAccessType(request);
        List<ChannelSet> channelList = channelSetService.selectAuthChannels(accessType, user.getOrgId(),user.getTenantId());
        view.addObject("channelList",channelList);
        view.addObject("channelCode",channelCode);
        view.addObject("comefrom",comefrom);
        view.addObject("transactionId",transactionId);
        view.addObject("provinceList",baseDataService.getProv(1));
        return view;
    }

    @PostMapping("/virtualList.json")
    @Function("trans.finTransaction.virtual.query")
    @ResponseBody
    public JsonResult<PageQuery> virtualList(FinTransaction condtion,HttpServletRequest request,String channelCode,String transactionIds)
    {
        CoreUser user = getLoginUser(request);
        if(StringUtils.isNotEmpty(channelCode)){
            condtion.setChannel(channelCode);
        }
        if(StringUtils.isNotEmpty(transactionIds)){
            condtion.setTransactionId(transactionIds);
        }
        condtion.setTenantId(user.getTenantId());
        if(StringUtils.isNotEmpty(condtion.getTransactionId())      ){
            condtion.setTransactionId("%"+condtion.getTransactionId()+"%");
        }
        if(StringUtils.isNotEmpty(condtion.getCustomerId())      ){
            condtion.setCustomerId("%"+condtion.getCustomerId()+"%");
        }
        if(StringUtils.isNotEmpty(condtion.getOrderId())      ){
            condtion.setOrderId("%"+condtion.getOrderId()+"%");
        }
        if(StringUtils.isNotEmpty(condtion.getTradeNo())      ){
            condtion.setTradeNo("%"+condtion.getTradeNo()+"%");
        }
        if(StringUtils.isNotEmpty(condtion.getBdOrder())&&condtion.getBdOrder().trim().length()==7){
            condtion.setTransactionId(condtion.getBdOrder().substring(0,4)+"%");
            condtion.setOrderId(condtion.getBdOrder().substring(4)+"%");
        }
        PageQuery page = condtion.getPageQuery();
        finTransactionService.queryVirtualByCondition(page);
        return JsonResult.success(page);
    }

    @GetMapping("/details.do")
    @ResponseBody
    public ModelAndView details(String transactionId) {
        ModelAndView view = new ModelAndView(MODEL + "/details.html");
        FinTransaction finTransaction = finTransactionService.selectTranInfoById(transactionId);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if(finTransaction.getCreateTime()!=null){
            finTransaction.set("createTimeText",sdf.format(finTransaction.getCreateTime()));
        }
       if(finTransaction.getPayTime()!=null) {
           finTransaction.set("payTimeText", sdf.format(finTransaction.getPayTime()));
       }
        String majorTypeText = "";
        if(finTransaction.get("majorTypeId")!=null){
            int majorType = Integer.parseInt(finTransaction.get("majorTypeId").toString());
            if(majorType==1){
                majorTypeText = "文科";
            }else if(majorType==2){
                majorTypeText = "理科";
            }else if(majorType==3){
                majorTypeText = finTransaction.get("shortGroup").toString().replaceAll(",","");
            }
        }
        finTransaction.set("majorTypeText",majorTypeText);
        String refundTimeText = "";
        if(finTransaction.getRefundTime()!=null){
            refundTimeText = sdf.format(finTransaction.getRefundTime());
        }
        finTransaction.set("refundTimeText",refundTimeText);
        String withdrawTimeText = "";
        if(finTransaction.get("withdrawTime")!=null){
            withdrawTimeText = sdf.format(finTransaction.get("withdrawTime"));
        }
        finTransaction.set("withdrawTimeText",withdrawTimeText);

//        退款状态 1、申请，待审核，2、审核驳回，3、审核通过，待退款，4、已退款，-4、退款时接口异常
        String refundStatusText = "";
        if(finTransaction.get("refundStatus")!=null){
            int majorType = Integer.parseInt(finTransaction.get("refundStatus").toString());
            if(majorType==1){
                refundStatusText = "待审核";
            }else if(majorType==2){
                refundStatusText = "审核驳回";
            }else if(majorType==3){
                refundStatusText = "待退款";
            }else if(majorType==4){
                refundStatusText = "已退款";
            }else if(majorType==-4){
                refundStatusText = "退款时接口异常";
            }
        }
        finTransaction.set("refundStatusText",refundStatusText);
        String payMethodText = "";
        Integer payMethod = finTransaction.getPayMethod();
        if(payMethod!=null){
            if(payMethod<10){
                payMethodText ="微信支付";
            }else  if(payMethod<20){
                payMethodText ="支付宝支付";
            }

        }
        finTransaction.set("payMethodText",payMethodText);
        finTransaction.set("payFlagText",finTransactionService.selectDictName("PAY_FLAG",finTransaction.getPayFlag()));

        view.addObject("finTrans",finTransaction);
        return view;
    }


    @RequestMapping("/virtualRefund.do")
    @Function("trans.finTransaction.virtual.refund")
    public ModelAndView virtualRefundPage(String transactionId,String customerId) {
        ModelAndView view = new ModelAndView(MODEL + "/virtualRefund.html") ;
        FinTransaction finTransaction = new FinTransaction();
        finTransaction.setTransactionId(transactionId);
        PageQuery page = finTransaction.getPageQuery();
        finTransactionService.queryVirtualByCondition(page);
        finTransaction = (FinTransaction) page.getList().get(0);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if(finTransaction.getCreateTime()!=null){
            finTransaction.set("createTimeText",sdf.format(finTransaction.getCreateTime()));
        }
        view.addObject("finTrans",finTransaction);
        Map<String,Object> param = new HashMap<>();
        //查询退款记录
        param.put("customerId",customerId);
        param.put("refundStatus",4);
        view.addObject("refundCount",sqlManager.intValue("trans.finTransaction.queryRefundCount",param));
        //查询退款声请记录
        param.put("refundStatus",1);
        view.addObject("applyCount",sqlManager.intValue("trans.finTransaction.queryRefundCount",param));

        return view;
    }


    @PostMapping("/virtualRefund.json")
    @Function("trans.finTransaction.virtual.refund")
    @ResponseBody
    public JsonResult virtualRefund(@RequestParam(required = true)String transactionId,
                             @RequestParam(required = true)String reason,MultipartFile imgFile) {
        JsonResult result = JsonResult.success();
        String dir = DateUtil.now("yyyyMMdd");
        String subPath = "/images/refund/"+dir+"/";
        String bucketName = "sdxcomm";

        FinTransaction transaction = finTransactionService.queryById(transactionId);
        if ( transaction==null){
            result = JsonResult.failMessage("交易单不存在。");
            return result;
        }
        CoreUser user = platformService.getCurrentUser();
        FinTransactionRefund transactionRefund = new FinTransactionRefund();
        if (!FileUtils.isEmptyFile(imgFile)) {
            try
            {
                String imgFileNamePair = FileUtils.upload(subPath,imgFile);
                String imgStoreFile = imgFileNamePair.split("::")[0];
                imgStoreFile = subPath+imgStoreFile;
                AliOSSApi.uploadLocalFile(FileUtils.getRoot()+imgStoreFile,bucketName,imgStoreFile.substring(1));
                String imgUrl = "https://sdxcomm."+ ConfigService.ossDomain+imgStoreFile;
                transactionRefund.setAttachFile(imgUrl);
                //baseMessage.setChannelCode(",miniprogram,");
                resCloudFileService.insertResFile(ResCloudFile.ALI,imgStoreFile,imgUrl,"a","退款");
            }catch(Exception e) {
                e.printStackTrace();
                result.setCode(JsonReturnCode.IO_ERROR.getCode());
                result.setMsg(e.getMessage());
            }
        }
        //1、生成退款记录
        transactionRefund.setOperatorId(user.getId().intValue());
        transactionRefund.setOperatorName(user.getName());
        transactionRefund.setApplyTime(new Date());
        transactionRefund.setRefundApply(transaction.getTotalMoney());
        transactionRefund.setRefundId(UUIDUtil.uuid());
        transactionRefund.setRefundReason(reason);
        transactionRefund.setRefundStatus(1);
        transactionRefund.setTransactionId(transactionId);
        refundService.save(transactionRefund);
        FinTransaction finTransaction = new FinTransaction();
        finTransaction.setTransactionId(transactionId);
        finTransaction.setPayFlag(3);
        finTransactionService.updateTemplate(finTransaction);
        return result;
    }


    @PostMapping("/payFlag.json")
    @Function("trans.finTransaction.virtual.payFlag")
    @ResponseBody
    public JsonResult payFlag(@RequestParam(required = true)String transactionId){
        FinTransaction transaction = new FinTransaction();
        transaction.setTransactionId(transactionId);
        transaction.setPayFlag(2);
        finTransactionService.updateTemplate(transaction);
        return JsonResult.success();
    }
}
